/**
 * mstdio.c
 *
 *  Created on: 2019-09-05
 *      Author: chenshisheng
 */

#include <mstdio.h>
#include <serial.h>
#include <stdarg.h>

#include "stream/chprintf.h"
#include "stream/mem_stream.h"
//#include "active.h"
#include "hw.h"

#if 1
#include "stream/serial_stream.h"

static SerialStream_t _stdio;
static IoStream_t _stdioWithoutBuf;

static bool _Rx(Serial_t serial, uint8_t b)
{
    Stream_t *stream;

    if((b == '\n') || (b == '\r'))
    {
        // 发送消息给shell
        stream = & _stdio.stream;
        MsgQueue_Send(MsgQueue_Id_ShellLineIn, & stream, sizeof(stream));
    }

    return true;
}

static void _AtStart(Serial_t serial)
{
    UNUSED(serial);

//    HW_Config(HW_Out_UsartDE, HW_State_Active);
}

static void _AtEnd(Serial_t serial)
{
    UNUSED(serial);

//    HW_Config(HW_Out_UsartDE, HW_State_Inactive);
}

static int _IoPut(void *instance, unsigned char b)
{
    IoStream_t *is = instance;
    Serial_t serial = (Serial_t)is->userData;

    Serial_SendByteWithoutBuffer(serial, b);
    return 1;
}

static int _IoGet(void *instance, unsigned char *pb)
{
    SerialStream_t *ss = instance;
    Serial_t serial = (Serial_t)ss->userData;

    return (Serial_RecvByteWithoutBuffer(serial, pb) == 0) ? 1 : 0;
}

void MStdio_Init(void)
{
    SerialStream_Init(&_stdio, STDIO_SERIAL);
    Serial_SetCallbacks(STDIO_SERIAL, _AtStart, _AtEnd, _Rx);

    IoStream_InitWithoutBuffer(&_stdioWithoutBuf, _IoPut, _IoGet, STDIO_SERIAL);

    debug("MStdio Init\n");
}

#else
#include "stream/null_stream.h"

#define _stdioWithoutBuf _stdio
static NullStream_t _stdio;

void MStdio_Init(void)
{
    NullStream_Init(&_stdio);
}
#endif
int printf(const char *fmt, ...)
{
    va_list args;
    int n;

    va_start(args, fmt);
    Stream_MutexWait(& _stdio);
    n = chvprintf(& _stdio, fmt, args);
    Stream_MutexRelease(& _stdio);
    va_end(args);

    return n;
}

int vprintf(const char *fmt, va_list vargs)
{
    return chvprintf(&_stdio, fmt, vargs);
}

int puts(const char *str)
{
    int n = 0;

    Stream_MutexWait(& _stdio);
    while(*str != '\0')
    {
        n += Stream_Put(& _stdio, *str++);
    }

    n += Stream_Put(& _stdio, '\r');
    n += Stream_Put(& _stdio, '\n');

    Stream_MutexRelease(& _stdio);
    return n;
}

int mprintf(const char *fmt, ...)
{
    va_list args;
    int n;
    MemStream_t mem;
    uint8_t buf[128];

    MemStream_Init(&mem, buf, sizeof(buf));

    va_start(args, fmt);
    Stream_MutexWait(& mem);
    n = chvprintf(& mem, fmt, args);
    Stream_MutexRelease(& mem);
    va_end(args);

    MsgQueue_Send(MsgQueue_Id_Printf, buf, n);
    return n;
}

void Mstdio_OnPrintf(const MsgQueue_Msg_t *msg)
{
    Stream_Write(&_stdio, msg->data, msg->size);
}

int wprintf(const char *fmt, ...)
{
    va_list args;
    int n;

    va_start(args, fmt);
    Stream_MutexWait(& _stdio);
    n = chvprintf(& _stdioWithoutBuf, fmt, args);
    Stream_MutexRelease(& _stdio);
    va_end(args);

    return n;
}
